package com.mstar.qs.common.jmx;

import java.lang.management.ManagementFactory;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.HashMap;

import javax.management.InstanceAlreadyExistsException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;

import org.apache.log4j.Logger;

public class MBManager extends HashMap<Object, MBeanAgent> {

	private static MBManager instance = new MBManager();
	public static long counter = 0;
	private static Logger log = Logger.getLogger(MBManager.class);

	public static MBManager getInstance() {
		return instance;
	}

	public static MBeanServer mBeanServer;
	public static final String SESSION_MBEAN_NAME = "mbname";

	private boolean isInit = false;

	public synchronized void putMBean(Object object, MBeanAgent agent) {
		this.put(object, agent);
		if (isInit) {
			registerMMBean(agent);
		}
	}

	public synchronized void init() {
		log.info("Begin to register MBeans...");
		for (MBeanAgent agent : this.values()) {
			registerMMBean(agent);
		}
		isInit = true;
	}
	
	public boolean registableMBean() {
		return mBeanServer!=null;
	}

	private void registerMMBean(MBeanAgent agent) {

		try {
			// log.info("Register MBean: " +
			// agent.getObjectNameStr());
			ObjectName objectName = new ObjectName(agent.getObjectNameStr()
					+ ".." + String.valueOf(++counter));
			// agent.setRegisterName(objectName);
			if (!mBeanServer.isRegistered(objectName)) {
				mBeanServer.registerMBean(agent, objectName);
			}
			agent.setName(objectName);
		} catch (InstanceAlreadyExistsException e) {
			e.printStackTrace();
		} catch (MBeanRegistrationException e) {
			e.printStackTrace();
		} catch (NotCompliantMBeanException e) {
			e.printStackTrace();
		} catch (MalformedObjectNameException e) {
			e.printStackTrace();
		} catch (NullPointerException e) {
			e.printStackTrace();
		}
	}

	public void unregisterMBean(Object dataSender) {
		MBeanAgent agent = this.remove(dataSender);
		destroyMBean(agent);
	}

	private void destroyMBean(MBeanAgent agent) {
		if (agent == null)
			return;
		try {
			// log.info("Unregister MBean: " + agent.getObjectNameStr());

			if (agent != null) {
				ObjectName name = agent.getName();

				if (ManagementFactory.getPlatformMBeanServer().isRegistered(
						name))
					try {
						ManagementFactory.getPlatformMBeanServer()
								.unregisterMBean(name);
						// log.info("Unregist this Mbean. ObjectName: "+name.toString());
					} catch (MBeanRegistrationException e) {
						e.printStackTrace();
					} catch (InstanceNotFoundException e) {
						e.printStackTrace();
					}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void initJMXServer(String host, int jmxPort, int rmiPort) {

		mBeanServer = ManagementFactory.getPlatformMBeanServer();
		JMXConnectorServer cs = null;
		try {
			Registry registry = null;
			try {
				registry = LocateRegistry.getRegistry(jmxPort);
				registry.list();
			} catch (final Exception e) {
				try {
					registry = LocateRegistry.createRegistry(jmxPort);
				} catch (final Exception ee) {
					ee.printStackTrace();
				}
			}

			String jmxUrl = "service:jmx:rmi://" + host + ":" + rmiPort
					+ "/jndi/rmi://" + host + ":" + jmxPort + "/server";
			log.info("JMX connector URL:\t" + jmxUrl);
			JMXServiceURL url = new JMXServiceURL(jmxUrl);
			cs = JMXConnectorServerFactory.newJMXConnectorServer(url, null,
					mBeanServer);

			cs.start();

		} catch (Exception e) {
			System.err
					.println("Can not start JMX connector server. Program will exit.");
			e.printStackTrace();
			System.exit(-1);
		}
	}

	public static void unRegisterMBean(ObjectName o) {
		if (ManagementFactory.getPlatformMBeanServer().isRegistered(o))
			try {
				ManagementFactory.getPlatformMBeanServer().unregisterMBean(o);
			} catch (MBeanRegistrationException e) {
				e.printStackTrace();
			} catch (InstanceNotFoundException e) {
				e.printStackTrace();
			}

	}
}
